﻿
Imports System.IO
Imports System.Drawing
Imports std

Public Class drawer
    Inherits cacheProcessor

    Public Const _pathidentity As String = "/draw/"

    Public Class query
        Public Const width As String = "w"
        Public Const height As String = "h"
        Public Const filter As String = "f"
    End Class

    Protected Overrides Function normalRetiredTicks() As Long
        Return secondsToTicks(10)
    End Function

    Public Overrides Function pathidentity() As String
        Return _pathidentity
    End Function

#If RETIRED Then
    Protected Overrides Sub addresponseHeaders(ByVal context As httpContext)
        MyBase.addresponseHeaders(context)
        context.setcontentType(network.http.contentType.imagejpeg)
    End Sub
#End If

    Public Shared Function generateDrawerUrl(ByVal context As httpContext) As String
        Dim url As String = Nothing
        url = _pathidentity + strmid(context.url().path, strlen(network.pathSeperator))
        If context.url().queryExist(query.filter) Then
            url = urlUtils.appendQuery(url, query.filter, context.url().query(query.filter))
        End If
        Return url
    End Function

    Private Function timenormalize(ByVal s As String, ByRef rtn As Int64) As Boolean
        Dim result As Date = Nothing
        If Not Date.TryParse(s, result) Then
            Return False
        End If
        rtn = ticksToSeconds(result.Ticks())
        Return True
    End Function

    Protected Overrides Function processImpl(ByVal context As httpContext) As Boolean
        Const MAX_COUNT_FOR_EACH_COUNTER As Int64 = 256
        Dim path As String = Nothing
        path = [delegate].fullpath(context, strlen(pathidentity()))
        If File.Exists(path) Then
            Dim reader As StreamReader = Nothing
            Try
                reader = New StreamReader(New FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
            Catch ex As Exception
                raiseError("cannot read file " + path + ", ignore. ex " + ex.Message, errorHandle.errorType.warning)
                Return False
            End Try

            Dim filter As String = Nothing
            filter = context.url().query(query.filter)

            Dim m As map(Of String, vector(Of pair(Of Int64, Int64))) = Nothing
            m = New map(Of String, vector(Of pair(Of Int64, Int64)))()
            Dim firstTime As Int64 = npos
            Dim line As String = Nothing
            line = reader.ReadLine()
            While Not line Is Nothing
                Dim timeStr As String = Nothing
                Dim time As Int64 = Nothing
                Dim name As String = Nothing
                Dim count As Int64
                If Not counter.breakupCounterMsg(line, timeStr, name, count) OrElse _
                   Not timenormalize(timeStr, time) Then
                    raiseError("cannot breakup counter message, " + line + ", ignore.", errorHandle.errorType.warning)
                Else
                    If firstTime = npos Then
                        firstTime = time
                    End If
                    If isemptystring(filter) OrElse fitfilter(filter, name, False) Then
                        Dim it2 As map(Of String, vector(Of pair(Of Int64, Int64))).iterator = Nothing
                        it2 = m.find(name)
                        If it2 = m.end() Then
                            it2 = m.insert(name, New vector(Of pair(Of Int64, Int64))())
                        End If
                        With (+it2).second
                            If .size() < MAX_COUNT_FOR_EACH_COUNTER OrElse _
                               rnd(0, 1) >= reader.BaseStream().Position() / reader.BaseStream().Length() Then
                                .push_back(make_pair(time - firstTime, count))
                                If .size() > MAX_COUNT_FOR_EACH_COUNTER Then
                                    .erase(rnd(0, .size(), True))
                                End If
                            End If
                        End With
                    End If
                End If
                line = reader.ReadLine()
            End While

            Dim it As map(Of String, vector(Of pair(Of Int64, Int64))).iterator = Nothing
            Dim i As Int64
            Dim bmp As Bitmap = Nothing
            Dim brush As Brush = Nothing
            Dim graph As Graphics = Nothing
            Dim width As Int64 = 640
            Dim height As Int64 = 480

            If context.url().queryExist(query.width) Then
                width = context.url().queryInt64(query.width)
            End If
            If context.url().queryExist(query.height) Then
                height = context.url().queryInt64(query.height)
            End If
            Const textEm As Byte = 12
            Dim font As Font = Nothing
            font = New Font(Drawing.FontFamily.GenericMonospace, textEm, FontStyle.Regular, GraphicsUnit.Pixel)
            bmp = New Bitmap(width, height, Drawing.Imaging.PixelFormat.Format32bppArgb)
            graph = Graphics.FromImage(bmp)
            graph.Clear(Color.White)
            i = 0
            it = m.begin()
            While it <> m.end()
                If Not graphUtils.drawLineChart(bmp, (+it).second, width:=width, height:=height, brushtext:=brush) Then
                    raiseError("cannot draw line chart for " + (+it).first + ", ignore.", errorHandle.errorType.warning)
                End If
                Try
                    graph.DrawString((+it).first, font, brush, 8, (textEm + 2) * i)
                Catch ex As Exception
                    raiseError("cannot draw color string to bitmap, ignore. ex " + ex.Message, _
                               errorHandle.errorType.warning)
                End Try
                it += 1
                i += 1
            End While

            graph.Dispose()
            bmp.Save(context.buff, Drawing.Imaging.ImageFormat.Jpeg)
            context.setcontentType(network.http.contentType.imagejpeg)
            Return True
        Else
            Return False
        End If
    End Function
End Class
